package com.unswift.cloud.service.auth;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;
import com.unswift.cloud.adapter.system.auth.SystemResourceAdapter;
import com.unswift.cloud.adapter.system.auth.SystemResourceInputAdapter;
import com.unswift.cloud.adapter.system.auth.SystemResourceOutputAdapter;
import com.unswift.cloud.adapter.system.auth.SystemRoleAdapter;
import com.unswift.cloud.adapter.system.auth.SystemRoleInputAdapter;
import com.unswift.cloud.adapter.system.auth.SystemRoleOutputAdapter;
import com.unswift.cloud.adapter.system.auth.SystemRoleResourceAdapter;
import com.unswift.cloud.adapter.system.auth.SystemUserRoleAdapter;
import com.unswift.cloud.annotation.logger.OperatorLogger;
import com.unswift.cloud.enums.OperatorTypeEnum;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleAuthorizeInputUpdateBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleAuthorizeOutputUpdateBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleAuthorizeTreeBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleAuthorizeViewBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleCreateBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleDeleteBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRolePageBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleUpdateBo;
import com.unswift.cloud.pojo.bo.system.role.SystemRoleViewBo;
import com.unswift.cloud.pojo.bo.system.role.resource.SystemRoleResourceUpdateBo;
import com.unswift.cloud.pojo.bo.system.role.resource.SystemRoleResourceUpdateListBo;
import com.unswift.cloud.pojo.dao.sql.Sql;
import com.unswift.cloud.pojo.dao.system.resource.SystemResourceDataDo;
import com.unswift.cloud.pojo.dao.system.resource.SystemResourceSearchDo;
import com.unswift.cloud.pojo.dao.system.resource.input.SystemResourceInputDataDo;
import com.unswift.cloud.pojo.dao.system.resource.output.SystemResourceOutputDataDo;
import com.unswift.cloud.pojo.dao.system.role.SystemRoleDataDo;
import com.unswift.cloud.pojo.dao.system.role.SystemRoleDeleteDo;
import com.unswift.cloud.pojo.dao.system.role.SystemRoleInsertDo;
import com.unswift.cloud.pojo.dao.system.role.SystemRolePageDo;
import com.unswift.cloud.pojo.dao.system.role.SystemRoleSingleDo;
import com.unswift.cloud.pojo.dao.system.role.SystemRoleUpdateDo;
import com.unswift.cloud.pojo.dao.system.role.input.SystemRoleInputDataDo;
import com.unswift.cloud.pojo.dao.system.role.input.SystemRoleInputInsertBatchDo;
import com.unswift.cloud.pojo.dao.system.role.input.SystemRoleInputInsertBatchItemDo;
import com.unswift.cloud.pojo.dao.system.role.output.SystemRoleOutputDataDo;
import com.unswift.cloud.pojo.dao.system.role.output.SystemRoleOutputInsertBatchDo;
import com.unswift.cloud.pojo.dao.system.role.output.SystemRoleOutputInsertBatchItemDo;
import com.unswift.cloud.pojo.dao.system.role.resource.SystemRoleResourceDataDo;
import com.unswift.cloud.pojo.dao.system.role.resource.SystemRoleResourceInsertBatchDo;
import com.unswift.cloud.pojo.dao.system.role.resource.SystemRoleResourceInsertBatchItemDo;
import com.unswift.cloud.pojo.dao.system.role.resource.SystemRoleResourceSearchDo;
import com.unswift.cloud.pojo.vo.page.PageVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleAuthorizeInputViewVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleAuthorizeOutputViewVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleAuthorizeTreeVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleAuthorizeViewVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleCreateVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleDeleteVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRolePageVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleUpdateVo;
import com.unswift.cloud.pojo.vo.system.role.SystemRoleViewVo;
import com.unswift.cloud.pojo.vo.system.role.resource.SystemRoleResourceUpdateVo;
import com.unswift.cloud.service.BaseService;
import com.unswift.cloud.utils.LoggerUtils;
import com.unswift.utils.ExceptionUtils;
import com.unswift.utils.ObjectUtils;

@Service
@Api(value="系统角色服务", author="liyunlong", date="2023-09-28", version="1.0.0")
public class SystemRoleService extends BaseService{
	
	@Autowired
	@ApiField("系统角色公共服务")
	private SystemRoleAdapter systemRoleAdapter;
	
	@Autowired
	@ApiField("系统资源公共服务")
	private SystemResourceAdapter systemResourceAdapter;
	
	@Autowired
	@ApiField("系统角色资源公共服务")
	private SystemRoleResourceAdapter systemRoleResourceAdapter;
	
	@Autowired
	@ApiField("系统资源入参公共服务")
	private SystemResourceInputAdapter systemResourceInputAdapter;
	
	@Autowired
	@ApiField("系统资源出参公共服务")
	private SystemResourceOutputAdapter systemResourceOutputAdapter;
	
	@Autowired
	@ApiField("系统角色关联资源入参公共服务")
	private SystemRoleInputAdapter systemRoleInputAdapter;
	
	@Autowired
	@ApiField("系统角色关联资源出参公共服务")
	private SystemRoleOutputAdapter systemRoleOutputAdapter;
	
	@Autowired
	@ApiField("系统用户关联角色出参公共服务")
	private SystemUserRoleAdapter systemUserRoleAdapter;
	
	@ApiMethod(value="查询系统角色分页数据", params=@ApiField("分页对象，包含分页信息及查询条件"), returns=@ApiField("包含查询数据的分页对象"))
	public PageVo<SystemRolePageVo> findPageList(SystemRolePageBo searchBo){
		SystemRolePageDo search=this.convertPojo(searchBo, SystemRolePageDo.class);//将Bo转换为Do
		search.setFirstSize((search.getCurrPage()-1)*search.getPageSize());
		systemRoleAdapter.setCreateUserSql(search, "createUserName");//设置查询结果查询用户姓名
		systemRoleAdapter.setFieldToLike(search, "name", ObjectUtils.asList("t.name_", "t.key_"));//将name转为like查询
		systemRoleAdapter.addOrderBy(search, "change_time_", Sql.ORDER_BY_DESC);//update_time_倒叙
		PageVo<SystemRoleDataDo> page=systemRoleAdapter.findPageList(search);//将Do转换为Vo
		return this.convertPage(page, SystemRolePageVo.class);
	}
	
	@ApiMethod(value="查询系统角色详情", params=@ApiField("详情业务实体，包含id字段"), returns=@ApiField("系统角色详情数据"))
	public SystemRoleViewVo view(SystemRoleViewBo viewBo){
		SystemRoleSingleDo search=this.convertPojo(viewBo, SystemRoleSingleDo.class);
		SystemRoleDataDo single=systemRoleAdapter.findSingle(search);
		return this.convertPojo(single, SystemRoleViewVo.class);//将Do转换为Vo
	}

	@OperatorLogger(type = OperatorTypeEnum.CREATE)
	@ApiMethod(value="创建系统角色", params=@ApiField("创建的业务实体"), returns=@ApiField("创建结果{0：未创建，1：已创建}"))
	public SystemRoleCreateVo create(SystemRoleCreateBo createBo){
		LoggerUtils.setModule(systemRoleAdapter.getModule());//设置日志所属模块
		SystemRoleInsertDo insert=this.convertPojo(createBo, SystemRoleInsertDo.class);//将Bo转换为Do
		systemRoleAdapter.setInsertDefault(insert);//设置默认值
		int result=systemRoleAdapter.save(insert, true);
		LoggerUtils.setId(insert.getId());//创建日志需要设置数据id
		return new SystemRoleCreateVo(result);
	}
	
	@OperatorLogger(type = OperatorTypeEnum.UPDATE)
	@ApiMethod(value="更新系统角色", params=@ApiField("更新的业务实体"), returns=@ApiField("更新结果{0：未创建，1：已创建}"))
	public SystemRoleUpdateVo update(SystemRoleUpdateBo updateBo){
		LoggerUtils.setModule(systemRoleAdapter.getModule());//设置日志所属模块
		SystemRoleDataDo currRole=systemRoleAdapter.findById(updateBo.getId());
		LoggerUtils.setOriginalData(currRole);//设置日志原数据对象
		SystemRoleUpdateDo update=this.convertPojo(updateBo, SystemRoleUpdateDo.class);//将Bo转换为Do
		int result=systemRoleAdapter.update(update, true);
		return new SystemRoleUpdateVo(result);
	}
	
	@Transactional("systemTransactionManager")
	@OperatorLogger(type = OperatorTypeEnum.UPDATE, pkFileName = "roleId")
	@ApiMethod(value="更新角色的权限", params = {@ApiField("需要更新的角色权限的对象")}, returns = @ApiField("更新结果{0：未创建，1：已创建}") )
	public SystemRoleResourceUpdateVo updateAuthorize(SystemRoleResourceUpdateListBo updateBo) {
		LoggerUtils.setModule(systemRoleAdapter.getModule());//设置日志所属模块
		List<SystemRoleResourceDataDo> roleResourceList=systemRoleResourceAdapter.findByRoleId(updateBo.getRoleId());
		roleResourceList.forEach(rr -> {
			rr.setOpenInputName(cacheAdapter.findDictionaryValueByKey("", getLanguage(), getLanguage()));
		});
		
		List<SystemRoleResourceUpdateBo> currRoleResourceList=this.convertPojoList(roleResourceList, SystemRoleResourceUpdateBo.class);
		if(ObjectUtils.isNotEmpty(currRoleResourceList)) {
			for (SystemRoleResourceUpdateBo roleResource : currRoleResourceList) {
				if(!updateBo.getList().stream().filter(u -> u.getResourceId().equals(roleResource.getResourceId()) && u.getResetParam()).findAny().isEmpty()) {
					roleResource.setInputList(this.convertPojoList(systemRoleInputAdapter.findInputIdByRoleIdAndResourceId(roleResource.getRoleId(), roleResource.getResourceId(), false), SystemRoleAuthorizeInputUpdateBo.class));
					roleResource.setOutputList(this.convertPojoList(systemRoleOutputAdapter.findOutputIdByRoleIdAndResourceId(roleResource.getRoleId(), roleResource.getResourceId(), false), SystemRoleAuthorizeOutputUpdateBo.class));
				}	
			}
		}
		LoggerUtils.setOriginalData(new SystemRoleResourceUpdateListBo(currRoleResourceList));
		
		List<SystemRoleResourceInsertBatchItemDo> insertList=this.convertPojoList(updateBo.getList(), SystemRoleResourceInsertBatchItemDo.class);	
		for (SystemRoleResourceInsertBatchItemDo insertDo : insertList) {
			insertDo.setRoleId(updateBo.getRoleId());
			if(ObjectUtils.isEmpty(insertDo.getOpenInput())) {
				insertDo.setOpenInput(false);
			}
			if(ObjectUtils.isEmpty(insertDo.getOpenOutput())) {
				insertDo.setOpenOutput(false);
			}
		}
		systemRoleResourceAdapter.deleteByRoleId(updateBo.getRoleId());
		int result=systemRoleResourceAdapter.saveBatch(new SystemRoleResourceInsertBatchDo(insertList), false);
		for (SystemRoleResourceUpdateBo updateItemBo : updateBo.getList()) {
			if(updateItemBo.getResetParam()) {
				systemRoleInputAdapter.deleteByRoleIdAndResourceId(updateBo.getRoleId(), updateItemBo.getResourceId());
				systemRoleOutputAdapter.deleteByRoleIdAndResourceId(updateBo.getRoleId(), updateItemBo.getResourceId());
				if(ObjectUtils.isNotEmpty(updateItemBo.getOpenInput()) && updateItemBo.getOpenInput() && ObjectUtils.isNotEmpty(updateItemBo.getInputList())) {
					List<SystemRoleInputInsertBatchItemDo> insertInputList=this.convertPojoList(updateItemBo.getInputList(), SystemRoleInputInsertBatchItemDo.class);
					for(SystemRoleInputInsertBatchItemDo insertInput : insertInputList) {
						insertInput.setResourceId(updateItemBo.getResourceId());
						insertInput.setRoleId(updateBo.getRoleId());
					}
					systemRoleInputAdapter.saveBatch(new SystemRoleInputInsertBatchDo(insertInputList), false);
				}
				if(ObjectUtils.isNotEmpty(updateItemBo.getOpenOutput()) && updateItemBo.getOpenOutput() && ObjectUtils.isNotEmpty(updateItemBo.getOutputList())) {
					List<SystemRoleOutputInsertBatchItemDo> insertOutputList=this.convertPojoList(updateItemBo.getOutputList(), SystemRoleOutputInsertBatchItemDo.class);
					for(SystemRoleOutputInsertBatchItemDo insertOutput : insertOutputList) {
						insertOutput.setResourceId(updateItemBo.getResourceId());
						insertOutput.setRoleId(updateBo.getRoleId());
					}
					systemRoleOutputAdapter.saveBatch(new SystemRoleOutputInsertBatchDo(insertOutputList), false);
				}
			}
		}
		return new SystemRoleResourceUpdateVo(result);
	}
	
	@Transactional("systemTransactionManager")
	@OperatorLogger(type = OperatorTypeEnum.DELETE)
	@ApiMethod(value="删除系统角色", params=@ApiField("删除业务实体，包含id字段"), returns=@ApiField("删除结果{0：未创建，1：已创建}"))
	public SystemRoleDeleteVo delete(SystemRoleDeleteBo deleteBo){
		LoggerUtils.setModule(systemRoleAdapter.getModule());//设置日志所属模块
		SystemRoleDataDo role=systemRoleAdapter.findById(deleteBo.getId());
		ExceptionUtils.empty(role, "delete.object.not.exists", "角色信息");
		ExceptionUtils.trueException(systemUserRoleAdapter.existsByRoleId(deleteBo.getId()), "delete.existing.binding", String.format("角色(%s)", role.getName()), "用户");
		SystemRoleDeleteDo delete=this.convertPojo(deleteBo, SystemRoleDeleteDo.class);//将Bo转换为Do
		int result=systemRoleAdapter.delete(delete);
		systemRoleResourceAdapter.deleteByRoleId(delete.getId());
		systemRoleInputAdapter.deleteByRoleId(delete.getId());
		systemRoleOutputAdapter.deleteByRoleId(delete.getId());
		return new SystemRoleDeleteVo(result);
	}
	
	@ApiMethod(value="获取权限树数据，并根据当前角色判断是否被选中", params = {@ApiField("角色信息")}, returns = @ApiField("权限树结构"))
	public SystemRoleAuthorizeTreeVo findAuthorizeTree(SystemRoleAuthorizeTreeBo searchBo) {
		SystemRoleAuthorizeTreeVo root=new SystemRoleAuthorizeTreeVo(-1L, "权限", true, false);
		SystemResourceSearchDo search=new SystemResourceSearchDo();
		List<SystemResourceDataDo> list = systemResourceAdapter.findList(search);//查询权限列表
		if(ObjectUtils.isNotEmpty(list)) {
        	List<SystemResourceDataDo> rootList=list.stream().filter(r -> r.getType().equals("platform")).collect(Collectors.toList());//找到根节点
        	if(ObjectUtils.isEmpty(rootList)){
        		return root;
        	}
        	Set<Long> authorizedIds=new HashSet<Long>();
        	if(ObjectUtils.isNotEmpty(searchBo.getRoleId())){
        		SystemRoleResourceSearchDo search2=new SystemRoleResourceSearchDo();
        		search2.setRoleId(searchBo.getRoleId());
        		List<SystemRoleResourceDataDo> roleResourceList = systemRoleResourceAdapter.findList(search2);//查询当前角色拥有的权限
        		if(ObjectUtils.isNotEmpty(roleResourceList)) {
        			authorizedIds=roleResourceList.stream().map(rr -> rr.getResourceId()).distinct().collect(Collectors.toSet());
        		}        		
        	}
        	if(rootList.size()==1) {
        		root.setId(rootList.get(0).getId());
        		root.setTitle(rootList.get(0).getName());
        		systemResourceAdapter.parseAuthorizeToTree(list, root, authorizedIds);//将List转为Tree对象
        	} else {
        		List<SystemRoleAuthorizeTreeVo> childList=new ArrayList<SystemRoleAuthorizeTreeVo>();
        		SystemRoleAuthorizeTreeVo childNode;
        		for (SystemResourceDataDo resource : rootList) {
        			childNode=new SystemRoleAuthorizeTreeVo(resource.getId(), resource.getName());
        			childNode.setSpread(true);
        			childList.add(childNode);
        			systemResourceAdapter.parseAuthorizeToTree(list, childNode, authorizedIds);//将List转为Tree对象
				}
        		root.setChildren(childList);
        	}
        }
		return root;
	}
	
	@ApiMethod(value="获取权限明细数据-包括权限信息、入参列表、出参列表", params = {@ApiField("角色、单个权限信息")}, returns = @ApiField("权限明细数据"))
	public SystemRoleAuthorizeViewVo findAuthorizeView(SystemRoleAuthorizeViewBo viewBo) {
		SystemResourceDataDo resource=systemResourceAdapter.findById(viewBo.getResourceId());
		SystemRoleAuthorizeViewVo view=this.convertPojo(resource, SystemRoleAuthorizeViewVo.class);
		SystemRoleResourceDataDo data=systemRoleResourceAdapter.findByRoleIdAndResourceId(viewBo.getRoleId(), viewBo.getResourceId());
		if(ObjectUtils.isNotEmpty(data)){
			view.setOpenInput(data.getOpenInput());
			view.setOpenOutput(data.getOpenOutput());
		}else {
			view.setOpenInput(false);
			view.setOpenOutput(false);
		}
		List<SystemResourceInputDataDo> inputListDo = systemResourceInputAdapter.findByResourceId(viewBo.getResourceId());//获取资源入参列表
		List<SystemResourceOutputDataDo> outputListDo = systemResourceOutputAdapter.findByResourceId(viewBo.getResourceId());//获取资源出参列表
		List<SystemRoleAuthorizeInputViewVo> inputList = this.convertPojoList(inputListDo, SystemRoleAuthorizeInputViewVo.class);//转换为Vo列表
		List<SystemRoleAuthorizeOutputViewVo> outputList = this.convertPojoList(outputListDo, SystemRoleAuthorizeOutputViewVo.class); //转换为Vo列表
		if(ObjectUtils.isNotEmpty(inputList)) {//设置入参是否被选中
			List<SystemRoleInputDataDo> roleInputList=systemRoleInputAdapter.findInputIdByRoleIdAndResourceId(viewBo.getRoleId(), viewBo.getResourceId(), false);
			if(ObjectUtils.isNotEmpty(roleInputList)) {
				List<Long> roleInputIdList=roleInputList.stream().map(i -> i.getInputId()).collect(Collectors.toList());
				inputList.forEach(i -> {
					if(roleInputIdList.contains(i.getId())) {
						i.setChecked(true);
					}
				});;
			}		
		}
		if(ObjectUtils.isNotEmpty(outputList)) {//设置出参是否被选中
			List<SystemRoleOutputDataDo> roleOutputList=systemRoleOutputAdapter.findOutputIdByRoleIdAndResourceId(viewBo.getRoleId(), viewBo.getResourceId(), false);
			if(ObjectUtils.isNotEmpty(roleOutputList)) {
				List<Long> roleOutputIdList=roleOutputList.stream().map(i -> i.getOutputId()).collect(Collectors.toList());
				outputList.forEach(i -> {
					if(roleOutputIdList.contains(i.getId())) {
						i.setChecked(true);
					}
				});
			}
		}
		view.setInputList(inputList);//设置入参
		view.setOutputList(outputList);//设置出参
		return view;
	}
}
